﻿using Heng.Elements.Core.Model.Infrastructure.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Heng.Elements.Core.Model.Infrastructure.Policy
{
    public static class PolicyManager
    {
        /// <summary>
        /// Execute function using policy.
        /// </summary>
        /// <typeparam name="TRes"> Result type. </typeparam>
        /// <param name="func"> Function to execute. </param>
        /// <returns> Service response. </returns>
        public static ServiceResponse<TRes> Exec<TRes>(Func<ServiceResponse<TRes>, TRes> func)
        {
            // TO DO: use action codes to give a more specific context to service execution

            // service response
            ServiceResponse<TRes> response = new ServiceResponse<TRes>();

            try
            {
                TRes res = func(response);
                response.Data = res;
            }
            catch (Exception ex)
            {
                response.Success = false;

                // create message
                var msg = ex.Message;
                response.Messages.Add(new ServiceResponseMessage { Text = msg, Scope = ServiceResponseMessageGeneralScope.General, Type = ServiceResponseMessageType.Error });

                // TO DO: log exception
            }

            // if all went well then mark it as a success
            response.Success = true;

            return response;
        }

        /// <summary>
        /// Execute action using policy.
        /// </summary>
        /// <param name="action"> Action to execute. </param>
        /// <returns> Service response. </returns>
        public static ServiceResponse Exec(Action<ServiceResponse> action)
        {
            // service response
            ServiceResponse response = new ServiceResponse();

            var resAux = Exec<object>(resInner =>
                {
                    action(response);

                    return null;
                });

            response.Merge(resAux);

            return response;
        }
    }
}
